#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define BOLD_GRAY "\033[1;90m"
#define RED "\033[0;31m"
#define WHITE "\033[0;37m"
#define RESET "\033[0m"

// Структура для сигнатур
typedef struct {
    const char *name;
    const unsigned char *signature;
    size_t sig_len;
    const char *mime_type;
    int offset;  // Смещение для чтения сигнатуры
} Signature;

// Расширенная база сигнатур
static const Signature signatures[] = {
    {"PNG", (unsigned char *)"\x89PNG\r\n\x1A\n", 8, "image/png", 0},
    {"JPEG", (unsigned char *)"\xFF\xD8\xFF", 3, "image/jpeg", 0},
    {"ELF", (unsigned char *)"\x7F" "ELF", 4, "application/x-executable", 0},
    {"PDF", (unsigned char *)"%PDF-", 5, "application/pdf", 0},
    {"GIF", (unsigned char *)"GIF89a", 6, "image/gif", 0},
    {"GIF", (unsigned char *)"GIF87a", 6, "image/gif", 0},
    {"BMP", (unsigned char *)"BM", 2, "image/bmp", 0},
    {"WEBP", (unsigned char *)"RIFF....WEBP", 12, "image/webp", 0},
    {"MP3", (unsigned char *)"ID3", 3, "audio/mpeg", 0},
    {"WAV", (unsigned char *)"RIFF....WAVE", 12, "audio/wav", 0},
    {"FLAC", (unsigned char *)"fLaC", 4, "audio/flac", 0},
    {"MP4", (unsigned char *)"\x00\x00\x00\x20\x66\x74\x79\x70\x69\x73\x6F\x6D", 12, "video/mp4", 0}, // ftypisom
    {"MP4", (unsigned char *)"\x00\x00\x00\x18\x66\x74\x79\x70\x6D\x70\x34\x32", 12, "video/mp4", 0}, // ftypmp42
    {"MP4", (unsigned char *)"\x00\x00\x00\x1C\x66\x74\x79\x70\x64\x61\x73\x68", 12, "video/mp4", 0}, // ftypdash
    {"MKV", (unsigned char *)"\x1A\x45\xDF\xA3", 4, "video/x-matroska", 0},
    {"ZIP", (unsigned char *)"PK\x03\x04", 4, "application/zip", 0},
    {"TAR", (unsigned char *)"ustar", 5, "application/x-tar", 257}, // ustar at offset 257
    {"7Z", (unsigned char *)"\x37\x7A\xBC\xAF\x27\x1C", 6, "application/x-7z-compressed", 0},
    {"DOCX", (unsigned char *)"PK\x03\x04", 4, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", 0},
    {"XLSX", (unsigned char *)"PK\x03\x04", 4, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", 0},
    {"SQLITE", (unsigned char *)"SQLite format 3", 15, "application/x-sqlite3", 0},
    {"EXE", (unsigned char *)"MZ", 2, "application/x-msdownload", 0},
    {"ISO", (unsigned char *)"\x43\x44\x30\x30\x31", 5, "application/x-iso9660-image", 32769}, // CD001 at offset 32769
    {"OGG", (unsigned char *)"OggS", 4, "audio/ogg", 0},
    {"AVI", (unsigned char *)"RIFF....AVI ", 12, "video/x-msvideo", 0},
    {"RAR", (unsigned char *)"Rar!\x1A\x07\x00", 7, "application/x-rar-compressed", 0},
    {"EPUB", (unsigned char *)"PK\x03\x04", 4, "application/epub+zip", 0},
    {"ODT", (unsigned char *)"PK\x03\x04", 4, "application/vnd.oasis.opendocument.text", 0},
    {"SIXEL", (unsigned char *)"\x1B\x50\x71", 3, "image/sixel", 0},
    {NULL, NULL, 0, NULL, 0}
};

int module_09_run(const char *filename) {
    char log_msg[1024];

    FILE *file = fopen(filename, "rb");
    if (!file) {
        snprintf(log_msg, sizeof(log_msg), BOLD_GRAY " Library custom_signature: " RED "File type not recognized: %s" RESET, strerror(errno));
        printf("%s\n", log_msg);
        return 1;
    }

    int found = 0;
    for (int i = 0; signatures[i].name; i++) {
        fseek(file, signatures[i].offset, SEEK_SET);
        unsigned char *buffer = malloc(signatures[i].sig_len);
        if (!buffer) {
            snprintf(log_msg, sizeof(log_msg), BOLD_GRAY " Library custom_signature: " RED "Memory allocation failed" RESET);
            printf("%s\n", log_msg);
            fclose(file);
            return 1;
        }

        size_t read_bytes = fread(buffer, 1, signatures[i].sig_len, file);
        if (read_bytes >= signatures[i].sig_len &&
            memcmp(buffer, signatures[i].signature, signatures[i].sig_len) == 0) {
            snprintf(log_msg, sizeof(log_msg), BOLD_GRAY " Library custom_signature: " WHITE "Signature match: %s, MIME: %s" RESET,
                     signatures[i].name, signatures[i].mime_type);
            printf("%s\n", log_msg);
            found = 1;
            free(buffer);
            break;
        }
        free(buffer);
    }
    fclose(file);

    if (!found) {
        snprintf(log_msg, sizeof(log_msg), BOLD_GRAY " Library custom_signature: " RED "No known signature found" RESET);
        printf("%s\n", log_msg);
    }
    return 0;
}
